package com.googlecode.easyibatis.spring.dao;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.transaction.annotation.Transactional;

import com.googlecode.easyibatis.core.constants.CommonsConstants;
import com.googlecode.easyibatis.core.exception.EasyIbatisException;
import com.googlecode.easyibatis.core.model.Model;
import com.googlecode.easyibatis.core.model.annotation.Ibatis;
import com.googlecode.easyibatis.core.utils.ModelLoader;
import com.googlecode.easyibatis.core.utils.FilterUtils;
import com.googlecode.easyibatis.core.utils.ReflectionUtils;
import com.googlecode.easyibatis.core.utils.Sort;


/**
 * 
 */

/**
 * @author zxq
 * 
 */
public abstract class DAOSupportImpl<T extends Model, PK extends Serializable> extends AbstractSupport {
	protected final org.apache.commons.logging.Log logger = LogFactory.getLog(this.getClass());

	protected Class<T> modelClass;

	@Resource(name = CommonsConstants.SqlmapClient_Bean)
	protected SqlMapClientTemplate sqlMapClientSupport;

	/**
	 * 通过子类的泛型定义取得对象类型Class.
	 */
	public DAOSupportImpl() {
		this.modelClass = ReflectionUtils.getSuperClassGenricType(getClass());
	}

	/**
	 * 在构造函数中定义对象类型Class.
	 */
	public DAOSupportImpl(Class<T> modelClass) {
		this.modelClass = modelClass;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.dfzc.commons.Service#delete(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public void delete(T model) throws EasyIbatisException {
		try {
			Map param = ModelLoader.loadWriteModel(model);
			sqlMapClientSupport.getSqlMapClient().update("commons.delete", param);
		} catch (SQLException e) {
			throw parseException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.dfzc.commons.Service#findAll()
	 */
	public Collection<T> findAll() throws EasyIbatisException {
		return findAllByFilter(null, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.dfzc.commons.Service#findById(java.io.Serializable)
	 */
	@SuppressWarnings("unchecked")
	public T findById(PK id) throws EasyIbatisException {
		try {
			Map param = ModelLoader.loadSelectModel(modelClass);
			if (modelClass.getAnnotation(Ibatis.class) == null
					|| StringUtils.isBlank(modelClass.getAnnotation(Ibatis.class).findAllByFilter())) {
				throw new EasyIbatisException("无法获取@Ibatis");
			}
			param.put("id", id);
			return (T) sqlMapClientSupport.getSqlMapClient().queryForObject(
					modelClass.getAnnotation(Ibatis.class).findById(), param);
		} catch (SQLException e) {
			throw parseException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.dfzc.commons.Service#save(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public PK save(T model) throws EasyIbatisException {
		try {
			Map param = ModelLoader.loadWriteModel(model);
			return (PK) sqlMapClientSupport.getSqlMapClient().insert("commons.save", param);
		} catch (SQLException e) {
			throw parseException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.dfzc.commons.Service#total()
	 */
	public Long total() throws EasyIbatisException {
		return totalByFilter(null, null);
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.dfzc.commons.Service#totalByFilter(java.util.Map)
	 */
	@SuppressWarnings("unchecked")
	public Long totalByFilter(Map<String, ?> equalsFilter, Map<String, ?> likeFilter) throws EasyIbatisException {
		try {
			Map param = FilterUtils.handleEqualsFilterAndLikeFilter(modelClass, equalsFilter, likeFilter);
			return (Long) sqlMapClientSupport.getSqlMapClient().queryForObject("commons.totalByFilter", param);
		} catch (SQLException e) {
			throw parseException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.dfzc.commons.Service#update(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public void update(T model) throws EasyIbatisException {
		try {
			Map param = ModelLoader.loadWriteModel(model);
			sqlMapClientSupport.getSqlMapClient().update("commons.update", param);
		} catch (SQLException e) {
			throw parseException(e);
		}
	}

	/**
	 * 
	 * @param equalsFilter
	 * @param likeFilter
	 * @return
	 * @throws EasyIbatisException
	 */
	public Collection<T> findAllByFilter(Map<String, ?> equalsFilter, Map<String, ?> likeFilter, Sort... sorts)
			throws EasyIbatisException {
		return findAllByFilter(equalsFilter, likeFilter, null, null, sorts);
	}

	/**
	 * 
	 * @param equalsFilter
	 * @param likeFilter
	 * @param start
	 * @param limit
	 * @return
	 * @throws EasyIbatisException
	 */
	@SuppressWarnings("unchecked")
	public Collection<T> findAllByFilter(Map<String, ?> equalsFilter, Map<String, ?> likeFilter, Integer start,
			Integer limit, Sort... sorts) throws EasyIbatisException {
		try {
			if (modelClass.getAnnotation(Ibatis.class) == null
					|| StringUtils.isBlank(modelClass.getAnnotation(Ibatis.class).findAllByFilter())) {
				throw new EasyIbatisException("无法获取@Ibatis");
			}
			Map param = FilterUtils
					.handleEqualsFilterAndLikeFilterAndSorts(modelClass, equalsFilter, likeFilter, sorts);
			param.put("beginPage", start);
			param.put("endPage", limit);
			return sqlMapClientSupport.getSqlMapClient().queryForList(
					modelClass.getAnnotation(Ibatis.class).findAllByFilter(), param);
		} catch (SQLException e) {
			throw parseException(e);
		}
	}
}
